package ldh.im.fxgui.util;

import javafx.application.Platform;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.text.Text;
import javafx.stage.Popup;
import ldh.im.fxbase.component.EmojiPane;
import ldh.im.fxbase.component.ScreenCapturePane;
import ldh.im.fxbase.dao.ImSessionDao;
import ldh.im.fxbase.data.event.EventBusFactory;
import ldh.im.fxbase.data.event.NewMessageSession;
import ldh.im.fxbase.data.pojo.ImSession;
import ldh.im.fxbase.data.pojo.ImUser;
import ldh.im.fxbase.data.pojo.ImMessage;
import ldh.im.fxbase.util.*;
import ldh.im.fxgui.component.message.MessageListViewHandler;
import ldh.im.fxgui.component.message.bo.WrapImMessage;
import ldh.im.fxgui.service.MessageReadService;
import ldh.im.fxgui.controller.MainController;
import ldh.im.util.DateUtil;
import ldh.rpc.cache.RpcCacheService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.sql.SQLException;
import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

public class UiUtil {

    private static final Logger LOGGER = LoggerFactory.getLogger(UiUtil.class);

    private static final String cssLink = UiUtil.class.getResource("/css/html.css").toExternalForm();
    private static final String jsLink = UiUtil.class.getResource("/js/html.js").toExternalForm();
    private static final String initHtml = "<link rel=\"stylesheet\" href=\"" + cssLink +"\" /><script type=\"text/javascript\" src=\"" + jsLink + "\"></script>";

    private static final String initWebHtml = String.format("<html dir=\"ltr\"><head>%s</head><body contenteditable=\"true\"><span id=\"endSpan\"/></body></html>", initHtml);

    public static String getInitWebViewHtml() {
        return initWebHtml;
    }

    public static void setMainController(MainController mainController) {
        ImSingleton.getInstance().setMainController(mainController);
    }

    public static MainController getMainController() {
        return ImSingleton.getInstance().getMainController();
    }

    public static void switchMessageSession(ImSession imSession) {
        MainController mainController = ImSingleton.getInstance().getMainController();
        if (mainController != null) {
            mainController.switchMessageSession(imSession, null);
        }
    }

    public static EmojiPane getEmojiPane() {
        return ImSingleton.getInstance().getEmojiPane();
    }

    public static ScreenCapturePane getScreenCapturePane() {
        return ImSingleton.getInstance().getScreenCapturePane();
    }

    public static Popup getMainPopup() {
        return ImSingleton.getInstance().getMainPopup();
    }

    public static String getDataFile(String file) {
        String root = System.getProperty("user.dir");
        String dir = root + file;
        return dir;
    }

    /**
     * 获取数据存放路径
     * @param file
     * @return
     */
    public static String getDataFileOrCreate(String file) {
        String root = System.getProperty("user.dir");
        String dir = root + File.separator + file;
        File dirFile = new File(dir);
        while(!dirFile.exists()) dirFile.mkdirs();
        return "file:///" + dir;
    }

    public static boolean isWindows() {
        return System.getProperty("os.name").toLowerCase().contains("windows");
    }

    public static void runLater(Runnable runnable) {
        if (Platform.isFxApplicationThread()) {
            runnable.run();
            return;
        }
        Platform.runLater(()->{
            try {
                runnable.run();
            } catch (Exception e) {
                LOGGER.error("Platform Exception", e);
            }
        });
    }

    public static double calcHeight(String str, double width) {
        Text text = new Text(str);
        text.setWrappingWidth(width);
        new Scene(new Group(text));

        text.applyCss();

        final double height = text.getLayoutBounds().getHeight();
        return height;
    }

    public static LocalDateTime getServerDateTime() {
        return ImSingleton.getInstance().getData("SERVER_DATE_TIME");
    }

    public static void setServerDateTime(LocalDateTime serverDateTime) {
        ImSingleton.getInstance().putData("SERVER_DATE_TIME", serverDateTime);
    }

    public static synchronized void uiShowMessage(ImMessage message) {
        uiShowMessages(Arrays.asList(message));
    }

    /**
     * 前端展示接受到的消息
     * @param messages
     * @return
     */
    public static synchronized void uiShowMessages(List<ImMessage> messages) {
        if (messages.size() < 1) return;
        LOGGER.info("uiShowMessage start!");
        String userId = getLoginImUser().getUserId();

        ThreadPoolUtil.submit(()->{
            handleHotMessage(userId, messages);
        });

        MessageListViewHandler sendMessageHandler = ImSingleton.getInstance().getSendMessageHandler();
        if (sendMessageHandler != null) {
            ImSession imSession = sendMessageHandler.getMessageSession();
            ThreadPoolUtil.submit(()->{
                List<ImMessage> canShowMessages = messages.stream().filter(m->sendMessageHandler.canShowMessage(m)).collect(Collectors.toList());
                if (canShowMessages.size() > 0) {
                    FxThreadUtil.runLater(()->{
                        sendMessageHandler.addMessages(canShowMessages);
                    });

                    if (imSession != null) { // 前端能够展示消息，并发送消息已读事件
                        try {
                            MessageReadService.getInstance().asyHandleReadMessage(imSession.getId(), userId, messages);
                        } catch (Exception e) {
                            LOGGER.error("read action error!", e);
                        }
                    }
                }
            });
        }
    }

    /**
     * 前端UI更新消息
     * @param message  有附件的消息，更新附件接受状态，或消息是否发送成功，或消息是否已读
     */
    public static void uiUpdateMessage(ImMessage message) {
        if (ImSingleton.getInstance().getSendMessageHandler() != null) {
            WrapImMessage wrapImMessage = UiUtil.getWrapImMessage(message.getSessionId(), message.getServerId());
            if (wrapImMessage != null) {
                wrapImMessage.rebuildMessageStatus(message);
            }
//            ImSingleton.getInstance().getSendMessageHandler().updateMessage(message);
        }
    }

    public static void uiUpdateMessages(List<ImMessage> messages) {
        if (ImSingleton.getInstance().getSendMessageHandler() != null) {
            ImSingleton.getInstance().getSendMessageHandler().updateMessages(messages);
        }
    }

    /**
     * 前端UI刷新
     */
    public static void uiRefresh() {
        if (ImSingleton.getInstance().getSendMessageHandler() != null) {
            ImSingleton.getInstance().getSendMessageHandler().refresh();
        }
    }

    public static void setSendMessageHandler(MessageListViewHandler messageListViewHandler) {
        ImSingleton.getInstance().setSendMessageHandler(messageListViewHandler);
    }

    public static ImUser getLoginImUser() {
        return ImSingleton.getInstance().getLoginImUser();
    }

    public static void setLoginImUser(ImUser loginImUser) {
        ImSingleton.getInstance().setLoginImUser(loginImUser);
    }

    public static WrapImMessage getWrapImMessage(Long sessionId, String fileServerId) {
        RpcCacheService rpcCacheService = RpcUtil.getRpcBootstrap().getRpcConfig().getRpcCacheService();
        String key = "message_" + fileServerId;
        Object obj = rpcCacheService.getCache(key);
        if (obj != null) {
            rpcCacheService.setCache(key, System.currentTimeMillis(), DateUtil.toDate(LocalDateTime.now().plusMinutes(10)));
//            return (WrapImMessage) obj;
        }
        MessageListViewHandler messageListViewHandler = ImSingleton.getInstance().getSendMessageHandler();
        if (messageListViewHandler != null) {
            List<WrapImMessage> wrapImMessages = messageListViewHandler.getItems();
            for (WrapImMessage wrapImMessage : wrapImMessages) {
                if (!wrapImMessage.getImMessage().getSessionId().equals(sessionId)) return null;
                if (wrapImMessage.getImMessage().getServerId().equals(fileServerId)) {
                    rpcCacheService.setCache(key, System.currentTimeMillis(), DateUtil.toDate(LocalDateTime.now().plusMinutes(10)));
                    return wrapImMessage;
                }
            }
        }
        return null;
    }

    public static void deleteCacheWrapImMessage(String fileServerId) {
        RpcCacheService rpcCacheService = RpcUtil.getRpcBootstrap().getRpcConfig().getRpcCacheService();
        String key = "message_" + fileServerId;
        rpcCacheService.remove(key);
    }

    private static void handleHotMessage(String userId, List<ImMessage> messages){
        List<ImMessage> hotMessages = messages.stream().filter(m -> m.isReceiver(userId)).collect(Collectors.toList());
        if (hotMessages.size() > 0) {
            ImSessionDao sessionDao = new ImSessionDao();
            Long sessionId = 0L;
            Map<Long, List<ImMessage>> groupMessages = hotMessages.stream().collect(Collectors.groupingBy(ImMessage::getSessionId));
            for (Map.Entry<Long, List<ImMessage>> entry : groupMessages.entrySet()) {
                List<ImMessage> messageList = entry.getValue();
                if (messageList.size() < 1) continue;
                try {
                    sessionId = entry.getKey();
                    sessionDao.incrHotMessageNum(sessionId, entry.getValue().size());

                    EventBusFactory.getInstance().post(new NewMessageSession(entry.getKey()));
                } catch (SQLException e) {
                    LOGGER.error("增加热点数据失败, {}", e);
                }
                ImHotMessageSingleton.getInstance().incHotMessage(entry.getKey(), entry.getValue().size());
                ImMessage message = messageList.get(messageList.size()-1);
                String lastedMessage = MessageUtil.buildLastedMessage(message.getMessageType(), message.getContent());
                ImHotMessageSingleton.getInstance().changeLastedMessage(sessionId, lastedMessage);
            }
//            EventBusFactory.getInstance().post(new SessionChange(sessionId));
        }
    }
}
